package com.cctc.juc.source.Bitc.Ecas;

import sun.misc.VM;
import sun.reflect.Reflection;

import java.lang.reflect.Field;

/**
 * [Unsafe] 类
 * 描述信息：CAS 算法在操作系统层面对应于一条 CPU 原子指令（cmpxchg 指令），Java 通过 JNI 将其（C++ 代码）封装成了一个 Unsafe 类，提供给 Java 应用层进行使用。
 * 下面给出使用 Unsafe 类实现无锁（乐观锁）编程的大致步骤：
 * 1）获取 Unsafe 实例；
 * 2）调用 Unsafe 提供的字段（属性）偏移量方法，获取字段（属性）在内存中（相对于对象头）的偏移地址；
 * 3）调用 Unsafe 提供的 CAS 方法，完成 CAS 原子操作。
 * 4）若 3）操作失败，“自旋” 重复执行 2）、3），直到 CAS 操作成功。
 */
public final class AUnsafe {

    //####################[Unsafe 构造器]####################//

    /**
     * 使用 Unsafe 类实现无锁（乐观锁）编程的大致步骤：
     * 1）获取 Unsafe 实例；
     * 注意：通过源码发现，Unsafe 类是一个 final 修饰的 “不可变类”，且其 “不可变对象” 已经在内部构造好了。
     * - 对于 JVM 系统类，与其同属于系统类加载器，可以直接使用 Unsafe.getTheUnsafe() 工厂方法获取 Unsafe 实例；
     * - 但对于 App 应用类，无法直接使用此方法，只能通过反射的方式获取 theUnsafe 属性，定义一个辅助方法：
     * public static UnSafe getUnSafe() {
     * try {
     * Field theUnsafe = UnSafe.class.getDeclaredField("theUnsafe");
     * theUnsafe.setAccessible(true);
     * return (UnSafe) theUnsafe.get(null);
     * } catch (Exception e) {
     * throw new AssertionError();
     * }
     * }
     */

    private static final AUnsafe theUnsafe;

    private AUnsafe() {
    }

    static {
        theUnsafe = new AUnsafe();
    }

    public static AUnsafe getTheUnsafe() {
        Class var = Reflection.getCallerClass();
        // 注意，此处会进行系统类加载器校验，只开放于 JVM 系统类使用。
        if (!VM.isSystemDomainLoader(var.getClassLoader()))
            throw new SecurityException("Unsafe!!!");
        else return theUnsafe;
    }

    //####################[Unsafe 常用方法]####################//

    /**
     * 使用 Unsafe 类实现无锁（乐观锁）编程的大致步骤：
     * 2）调用 Unsafe 提供的字段（属性）偏移量方法，获取字段（属性）在内存中（相对于对象头）的偏移地址 offset；
     * - 获取 Object 实例或 Object[] 数组的总内存地址大小；
     * - 获取 Object 实例的静态属性的内存偏移地址；
     * - 获取 Object 实例的非静态属性的内存偏移地址；
     * - 获取 Object[] 数组的索引规模和第一个元素的内存偏移地址。
     */

    public native int addressSize();

    public native long staticFieldOffset(Field field);

    public native long objectFieldOffset(Field field);

    public native int arrayIndexScale(Class<?> array);

    public native int arrayBaseOffset(Class<?> array);

    /**
     * 使用 Unsafe 类实现无锁（乐观锁）编程的大致步骤：
     * 3）调用 Unsafe 提供的 CAS 方法，完成 CAS 原子操作。
     * [第一类]：getXXXVolatile()、putXXXVolatile()，直接基于（普通）变量的内存地址，且实现 volatile 语义（内存可见性、指令有序性）的读写操作；
     * - 其中 XXX 包括 Byte、Short、Int、Long、Float、Double、Char、Boolean、Object 等。
     * [第二类]：putOrderedXXX()，对于不需要保证写入立即可见的 volatile 变量，只保障写入操作的指令有序性；
     * - 其中 XXX 包括 Int、Long、Object 等。
     * [第三类]：getAndSetXXX()、getAndAddXXX()，直接基于（普通）变量的内存地址实现 CAS 原子操作，且依赖于 [第一类] 中的 getXXXVolatile() 方法只保证了读操作的 volatile 语义；
     * - 其中 XXX 包括 Int、Long、Object 等。
     * [第四类]：compareAndSwapXXX()，直接基于（普通）变量的内存地址实现 CAS 原子操作，但不具备 volatile 语义；
     * - 其中 XXX 包括 Int、Long、Object 等。
     */

    public native byte getXXXVolatile(Object o, long offset);

    public native void putXXXVolatile(Object o, long offset, byte update);

    public void putOrderedXXX(Object o, long offset, int x) {
        theInternalUnsafe.putXXXRelease(o, offset, x);
    }

    public final int getAndSetXXX(Object o, long offset, int newValue) {
        int oldValue;
        do {
            oldValue = this.getXXXVolatile(o, offset);
        } while (!this.compareAndSwapXXX(o, offset, oldValue, newValue));
        return oldValue;
    }

    public final int getAndAddXXX(Object o, long offset, int newValue) {
        int oldValue;
        do {
            oldValue = this.getXXXVolatile(o, offset);
        } while (!this.compareAndSwapXXX(o, offset, oldValue, oldValue + newValue));
        return oldValue;
    }

    public final native boolean compareAndSwapXXX(Object o, long offset, int expected, int update);

    /**
     * 使用 Unsafe 类实现无锁（乐观锁）编程的大致步骤：
     * 4）若 3）操作失败，“自旋” 重复执行 2）、3），直到 CAS 操作成功。
     * - 为了避免无效 “自旋” 造成的 CPU 开销问题，我们可以使用 Unsafe 提供的 park、unpark（线程阻塞与唤醒）方法，将发生 CAS 争抢的线程加入到一个排队队列中进行等待，降低 CAS 争抢的激烈程度，具体实现请参考 JUC 提供的 AQS（线程同步组件）组件。
     */

    public native void park(boolean isAbsolute, long time);

    public native void unpark(Object thread);

}
